home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / Python-1.4 / Lib / mimetools.py < prev    next >
Text File  |  1998-06-24  |  5KB  |  202 lines

  1. # Various tools used by MIME-reading or MIME-writing programs.
  2.  
  3.  
  4. import os
  5. import rfc822
  6. import string
  7. import tempfile
  8.  
  9.  
  10. # A derived class of rfc822.Message that knows about MIME headers and
  11. # contains some hooks for decoding encoded and multipart messages.
  12.  
  13. class Message(rfc822.Message):
  14.  
  15.     def __init__(self, fp, seekable = 1):
  16.         rfc822.Message.__init__(self, fp, seekable)
  17.         self.encodingheader = \
  18.             self.getheader('content-transfer-encoding')
  19.         self.typeheader = \
  20.             self.getheader('content-type')
  21.         self.parsetype()
  22.         self.parseplist()
  23.  
  24.     def parsetype(self):
  25.         str = self.typeheader
  26.         if str == None:
  27.             str = 'text/plain'
  28.         if ';' in str:
  29.             i = string.index(str, ';')
  30.             self.plisttext = str[i:]
  31.             str = str[:i]
  32.         else:
  33.             self.plisttext = ''
  34.         fields = string.splitfields(str, '/')
  35.         for i in range(len(fields)):
  36.             fields[i] = string.lower(string.strip(fields[i]))
  37.         self.type = string.joinfields(fields, '/')
  38.         self.maintype = fields[0]
  39.         self.subtype = string.joinfields(fields[1:], '/')
  40.  
  41.     def parseplist(self):
  42.         str = self.plisttext
  43.         self.plist = []
  44.         while str[:1] == ';':
  45.             str = str[1:]
  46.             if ';' in str:
  47.                 # XXX Should parse quotes!
  48.                 end = string.index(str, ';')
  49.             else:
  50.                 end = len(str)
  51.             f = str[:end]
  52.             if '=' in f:
  53.                 i = string.index(f, '=')
  54.                 f = string.lower(string.strip(f[:i])) + \
  55.                     '=' + string.strip(f[i+1:])
  56.             self.plist.append(string.strip(f))
  57.             str = str[end:]
  58.  
  59.     def getplist(self):
  60.         return self.plist
  61.  
  62.     def getparam(self, name):
  63.         name = string.lower(name) + '='
  64.         n = len(name)
  65.         for p in self.plist:
  66.             if p[:n] == name:
  67.                 return rfc822.unquote(p[n:])
  68.         return None
  69.  
  70.     def getparamnames(self):
  71.         result = []
  72.         for p in self.plist:
  73.             i = string.find(p, '=')
  74.             if i >= 0:
  75.                 result.append(string.lower(p[:i]))
  76.         return result
  77.  
  78.     def getencoding(self):
  79.         if self.encodingheader == None:
  80.             return '7bit'
  81.         return string.lower(self.encodingheader)
  82.  
  83.     def gettype(self):
  84.         return self.type
  85.  
  86.     def getmaintype(self):
  87.         return self.maintype
  88.  
  89.     def getsubtype(self):
  90.         return self.subtype
  91.  
  92.  
  93.  
  94.  
  95. # Utility functions
  96. # -----------------
  97.  
  98.  
  99. # Return a random string usable as a multipart boundary.
  100. # The method used is so that it is *very* unlikely that the same
  101. # string of characters will every occur again in the Universe,
  102. # so the caller needn't check the data it is packing for the
  103. # occurrence of the boundary.
  104. #
  105. # The boundary contains dots so you have to quote it in the header.
  106.  
  107. _prefix = None
  108.  
  109. def choose_boundary():
  110.     global _prefix
  111.     import time
  112.     import rand
  113.     if _prefix == None:
  114.         import socket
  115.         import os
  116.         hostid = socket.gethostbyname(socket.gethostname())
  117.         try:
  118.             uid = `os.getuid()`
  119.         except:
  120.             uid = '1'
  121.         try:
  122.             pid = `os.getpid()`
  123.         except:
  124.             pid = '1'
  125.         seed = `rand.rand()`
  126.         _prefix = hostid + '.' + uid + '.' + pid
  127.     timestamp = `int(time.time())`
  128.     seed = `rand.rand()`
  129.     return _prefix + '.' + timestamp + '.' + seed
  130.  
  131.  
  132. # Subroutines for decoding some common content-transfer-types
  133.  
  134. # XXX This requires that uudecode and mmencode are in $PATH
  135.  
  136. def decode(input, output, encoding):
  137.     if decodetab.has_key(encoding):
  138.         pipethrough(input, decodetab[encoding], output)
  139.     else:
  140.         raise ValueError, \
  141.               'unknown Content-Transfer-Encoding: %s' % encoding
  142.  
  143. def encode(input, output, encoding):
  144.     if encodetab.has_key(encoding):
  145.         pipethrough(input, encodetab[encoding], output)
  146.     else:
  147.         raise ValueError, \
  148.               'unknown Content-Transfer-Encoding: %s' % encoding
  149.  
  150. uudecode_pipe = '''(
  151. TEMP=/tmp/@uu.$$
  152. sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
  153. cat $TEMP
  154. rm $TEMP
  155. )'''
  156.  
  157. decodetab = {
  158.     'uuencode':        uudecode_pipe,
  159.     'x-uuencode':        uudecode_pipe,
  160.     'quoted-printable':    'mmencode -u -q',
  161.     'base64':        'mmencode -u -b',
  162. }
  163.  
  164. encodetab = {
  165.     'x-uuencode':        'uuencode tempfile',
  166.     'uuencode':        'uuencode tempfile',
  167.     'quoted-printable':    'mmencode -q',
  168.     'base64':        'mmencode -b',
  169. }
  170.  
  171. def pipeto(input, command):
  172.     pipe = os.popen(command, 'w')
  173.     copyliteral(input, pipe)
  174.     pipe.close()
  175.  
  176. def pipethrough(input, command, output):
  177.     tempname = tempfile.mktemp()
  178.     try:
  179.         temp = open(tempname, 'w')
  180.     except IOError:
  181.         print '*** Cannot create temp file', `tempname`
  182.         return
  183.     copyliteral(input, temp)
  184.     temp.close()
  185.     pipe = os.popen(command + ' <' + tempname, 'r')
  186.     copybinary(pipe, output)
  187.     pipe.close()
  188.     os.unlink(tempname)
  189.  
  190. def copyliteral(input, output):
  191.     while 1:
  192.         line = input.readline()
  193.         if not line: break
  194.         output.write(line)
  195.  
  196. def copybinary(input, output):
  197.     BUFSIZE = 8192
  198.     while 1:
  199.         line = input.read(BUFSIZE)
  200.         if not line: break
  201.         output.write(line)
  202.